package ch.ethz.fcl.metrobuzz.data.scene;

import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.tools.MBTools;

public class SceneBound {
	float minX = Float.MAX_VALUE;
	float maxX = -Float.MAX_VALUE;
	float minY = Float.MAX_VALUE;
	float maxY = -Float.MAX_VALUE;
	float minZ = Float.MAX_VALUE;
	float maxZ = -Float.MAX_VALUE;

	// keep the ratio of x / y
	private float ratio = 1;

	// bounds into the world coordinates
	private float worldMinX = -0.5f;
	private float worldMaxX = 0.5f;
	private float worldMinY = -0.3f;
	private float worldMaxY = 0.7f;
	private float worldMinZ = 0;
	private float worldMaxZ = 1;

	public void add(float x, float y, float z) {
		minX = Math.min(x, minX);
		maxX = Math.max(x, maxX);
		minY = Math.min(y, minY);
		maxY = Math.max(y, maxY);

		if (maxX - minX > 0 && maxY - minY > 0)
			ratio = (maxY - minY) / (maxX - minX);

		// System.out.println("Ratio: "+ratio);
		minZ = Math.min(z, minZ);
		maxZ = Math.max(z, maxZ);
	}

	public float normalizeX(float x) {
		return maxX - minX > 0 ? (x - minX) * (worldMaxX - worldMinX)
				/ (maxX - minX) + worldMinX : 0;
	}

	public float unNormalizeX(float x) {
		return maxX - minX > 0 ? (x - worldMinX) * (maxX - minX)
				/ (worldMaxX - worldMinX) + minX : 0;
	}

	public float normalizeY(float y) {
		return maxY - minY > 0 ? (y - minY) * (worldMaxY - worldMinY)
				/ (maxY - minY) * ratio + worldMinY : 0;
	}

	public float unNormalizeY(float y) {
		return maxY - minY > 0 ? (y - worldMinY) * (maxY - minY)
				/ (worldMaxY - worldMinY) + minY : 0;
	}

	public float normalizeZ(float z) {
		return maxZ - minZ > 0 ? (z - minZ) * (worldMaxZ - worldMinZ)
				/ (maxZ - minZ) + worldMinZ : 0;
	}

	public float unNormalizeZ(float z) {
		return maxZ - minZ > 0 ? z * (maxZ - minZ) + minZ : 0;
	}

	public float getXYRatio() {
		return ratio;
	}

	public float getMinX() {
		return minX;
	}

	public float getMinY() {
		return minY;
	}

	public float getMaxX() {
		return maxX;
	}

	public float getMaxY() {
		return maxY;
	}

	@Override
	public String toString() {
		return "[" + minX + " " + maxX + "][" + minY + " " + maxY + "][" + minZ
				+ " " + maxZ + "]";
	}

	/**
	 * WGS-84 in Zone 48N Coordinates x range: [346353.12 391710.2] y range:
	 * [136931.28 162470.3]
	 * 
	 * converted to GPS range latitude: [1.23849345888649, 1.46970028829146]
	 * longitude: [103.619027219961, 104.026554088695]
	 * 
	 * distance is 52.052 km
	 * 
	 * @return read screen length of the input distance
	 */
	public float getScreenDist(float distance) {
		float diaLen = MBTools.distance(worldMinX, worldMinY, worldMaxX,
				worldMaxY);

		return distance / 52052 * diaLen;
	}

	/**
	 * 
	 * @param p1
	 * @param p2
	 * @return real world distance (in meters) of two points on the screen
	 */
	public float getWorldDist(Point2D p1, Point2D p2) {
		return getWorldDist(p1.distance(p2));
	}

	/**
	 * 
	 * @param screen
	 *            length
	 * @return world distance (in meters) of screen length
	 */
	public float getWorldDist(float length) {
		float diaLen = MBTools.distance(worldMinX, worldMinY, worldMaxX,
				worldMaxY);

		return length / diaLen * 52052;
	}
}
